//
// memb_announcer.h
//

#ifndef KITTY_MEMB_ANNOUNCER_H
#define KITTY_MEMB_ANNOUNCER_H

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include "heartbeat.h"
#include "mcast_sender.h"

namespace kitty {

class memb_announcer
{
public:
    memb_announcer(boost::asio::io_service& io_service,
        const std::string& vnode_ip,
        unsigned short vnode_port,
        const boost::asio::ip::address& multicast_address,
        unsigned short multicast_port,
        long period = 1500)
      : timer_(io_service), period_(period),
        mcast_sender_(io_service, multicast_address, multicast_port)
    {
        // the first heartbeat packet
        hb_.ip = vnode_ip;
        hb_.port = vnode_port;
        hb_.timestamp = time(0);

        mcast_sender_.async_write(hb_,
            boost::bind(&memb_announcer::handle_async_write, this,
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
    }

private:
    void handle_async_write(const boost::system::error_code& e,
            std::size_t bytes_transferred)
    {
      if (!e)
      {
        // wait until the timer expires
        timer_.expires_from_now(boost::posix_time::milliseconds(period_));
        timer_.async_wait(boost::bind(&memb_announcer::handle_timeout,
                    this, boost::asio::placeholders::error));
      }
      else
      {
        std::cerr << "Something went wrong in mcast_sender::async_write: ";
        std::cerr << e.message() << std::endl;
        exit(1);
      }
    }

    void handle_timeout(const boost::system::error_code& error)
    {
        if (!error)
        {
            // local timestamp of the heartbeat packet
            hb_.timestamp = time(0);
            mcast_sender_.async_write(hb_,
                boost::bind(&memb_announcer::handle_async_write, this,
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred));
        }
    }

private:
    /// Heartbeat packet
    kitty::heartbeat hb_;

    /// The timer periodicaly sends heartbeat packets
    boost::asio::deadline_timer timer_;

    /// Period of heartbeating
    const long period_;

    /// The underlying multicast sending utility
    kitty::mcast_sender mcast_sender_;
};

} // namespace kitty

#endif // KITTY_MEMB_ANNOUNCER_H

